#ifndef _OBJ_H
#define _OBJ_H

#if C2504
#pragma message("vObject.h")
#endif

#include "Scene.h"
#include "ConfigFileParser.h"

class D3D11Mesh;
class Scene;
class RingManager;
class SurfaceManager;
class HazeManager;
class CloudManager;

class TerrainManager;

class vObject {
	friend class Scene;
	friend class D3D11Mesh;
public:
	vObject( OBJHANDLE _obj, Scene * scene );
	virtual ~vObject();

	virtual int VisEvent( DWORD msg, UINT context ) = 0;
	virtual MESHHANDLE clbkGetMesh( UINT idx ) = 0;

	void IsActive();
	virtual void SaveData();
	virtual void Update();
	virtual void Render() {	}

	static void InitRenderDot();
	void RenderDot();

	VECTOR3 GetCPos()	{	return CPos;	}
	double GetCDist()	{	return CDist;	}
	double GetAppRadius()	{	return apprad; }
	
	OBJHANDLE obj;
	double rad;
	bool active;
	Scene * GetScene() const { return m_scene; }
protected:
	Scene * m_scene;

	virtual void CheckResolution() = 0;
	void ConstructWorldMatrix( D3DXMATRIX *out, MATRIX3 *rot, VECTOR3 *pos );
	
	D3DXMATRIX mWorld, mWorld_new;
	double
		CDist,
		CDist_new,
		apprad;

	VECTOR3
		GPos,
		GPos_new,
		CPos,
		CPos_new;

	MATRIX3
		mROT,
		mROT_new;

	D3DXVECTOR4
		SunDir,
		SunDir_new;

	char name[64];
	int obj_type;

	static double SunSize;
	static VECTOR3 pSun;
	static Sun_spec def_SunLight;

public:
	D3DXVECTOR4 GetSunDir() { return SunDir; }
	MATRIX3 GetRotationMatrix() { return mROT; }
};

//=====================================
//		Planets
class vBase;
class AtmosphereMgr;

//base craters:
struct BaseCraterParams {
	//base lat, lng, radius of inner ring (area with 0.0 altitude), radius of outer ring (crater between inner and outer)
	double	lat, lng, minrad, maxrad;
};

struct CoverTypeParam {
	float width;
	float height;
	float ref_height;
	float max_dist;

	UINT32 flags;
	INT32 cidx;//"forest"
	INT32 midx;//microtexture
	INT32 tidx;//billboard texture array index
	//32
};

typedef struct PlanetaryConfig {
//configuration params for all graphics feature
	bool
		bPlanetaryShadows,			//enable shadows of planets (eclipses)
		bRingShadows,				//shadows of planetary rings

		bAdvancedClouds,			//volumetric clouds
		bParticleRings,				//particle rings

		bSpecularMap,				//use specular maps
		bNormalMap,					//use normal planetary maps
		bHeightMap,					//use _height.tex files
		bHeightMapGenerator,		//enable heightmap generator
		bLandCoverMap,				//use _lcover.tex files

		bTerrainShadows,			//terrain self-shadowing
		bDiffuseMicroTex,			//diffuse microtextures
		bNormalMicroTex,			//normal/bump microtextures
		bDisplacementMicroTex,		//displacement microtextures

		bTerrainDetails_Low,		//forest microtextures etc.
		bTerrainDetails_Average,	//enable average level details rendering
		bTerrainDetails_High,		//enable detail mesh rendering
		bTerrainDetails_Urban;		//parser !

	float
		maxTerrainElevation,
		minGenAltitude,
		maxGenAltitude,

		maxTerrainAlt,
		minNormalAlt,
		maxMicroTexDist,			//microtexture cutoff distance
		
		minEdgeTessFactor,
		maxEdgeTessFactor,

		DisplacementMicroTex_range,
		DisplacementMicroTex_mult,
		TerrainFlatMicroTex_mult,
		TerrainCoarseMicroTex_mult,
		TerrainLowDetailsMicroTex_mult,
		MicroTexTransAngles[2],

		TerrainDetails_Average_maxdist,	//0
		TerrainDetails_High_maxdist,	//0
		TerrainDetails_Urban_maxdist;	//0
	struct PAS_CONFIG {
		D3DXVECTOR3
			betaR,		//Rayleigh scattering coef.	[10^-6 m^-1]
			betaMSca,	//Mie scattering coef.
			betaMEx;	//Mie extinction coef.
		float
			HR,			//atmosphere thickness for rayleigh scattering (density = const)	[m]
			HM,			//atmosphere thickness for Mie scattering (density = const)			[m]
			mieG,		
			Rad_ground,	//planet base radius					[m]
			Rad_max,	//maximum radius of atmosphere			[m]
			Rad_limit,	//rendering radius of atmosphere ring	[m]
			AverageGroundReflectance;//depends on show dark is surface of planet	[0-1]
	} PASCfg;
	UINT
		maxTileResolution,
		AtmosphereType;
	std::vector<CoverTypeParam> CTP;//defines params necessary for detail render
} PlanetaryConfig;

class vPlanet : public vObject {
	friend class Scene;
	friend class vBase;
	friend class vVessel;
	friend class D3D11ParticleStream;
	friend class ExhaustStream;
	friend class ReentryStream;

	friend class TileManager;
	friend class TerrainManager;
	friend class TileRenderMgr;

public:
	vPlanet( OBJHANDLE _obj, Scene * scene );
	virtual ~vPlanet();

	int VisEvent( DWORD msg, UINT context )	{	return 0;	}
	MESHHANDLE clbkGetMesh( UINT idx )		{	return NULL;	}

	void Update();
	void Render();
	virtual void RenderShadowMap();

	ATM_FOG_PARAMS *GetAtmParams() { return &AP; };
	AtmosphereMgr *AtmM;	//any of 3 available atmosphere types
	TerrainManager *TerM;	//terrain
private:
	void ReadPlanetaryConfig();

	void CheckResolution();

	//basic atmosphere/haze params calculations
	void InitLegacyAtmosphere();
	bool InitFogParams( bool bfog );

	PlanetaryConfig CFG;
	D3D11Mesh *PlanetMesh;	//for asteroids

	struct CLOUDPRM {
		CloudManager *CM;	//clouds and cloud shadows
		D3DXMATRIX mW_cloud;
		D3DXMATRIX mW_cloudshadow;
		DWORD RenderMode;
		double cloud_rad;
		double viewap;
		bool bCloudShadow;
		float fShadowAlpha;
		double micro_alt0, micro_alt1;
	} *CloudData;

	struct RINGPRM {		//planetary rings
		RingManager *RM;
		double minrad;
		double maxrad;
		DWORD res;
	} *RingData;

//atmosphere params
	double Mass;			//mass of a a planet
	const ATMCONST *atmc;
	ATM_FOG_PARAMS AP;
	FogParam Fog;
	bool bFog;
	VECTOR3 gpos;
//misc
	float dist_scale;
	DWORD ring_res;		//0/1/2

	//***
	float rad, render_rad;
	bool bRipple;

	float shadow_alpha;
	bool bVesselShadows;

	int patchres;

	vBase **Base;
	DWORD nbase;

	//base craters:
	BaseCraterParams *BaseCraters;
};

//=====================================
//		Vessels
//=====================================

struct BBVertex {
	D3DXVECTOR3 pos;
	D3DXVECTOR2 tex;
};

struct cb_VS_Shadow
{
	D3DXMATRIX World;
	D3DXMATRIX ShadowVP;
};

struct cb_PS_Shadow
{
	D3DXVECTOR4 sunDirection;
	D3DXVECTOR4 shadowMapRefPoint;
	D3DXMATRIX  ShadowVP[4];
};

struct cb_GS_Shadow
{
	D3DXMATRIX  ShadowVP[4];
};

class vVessel : public vObject {
	friend class Scene;
	friend class D3D11ParticleStream;
	friend class ExhaustStream;
	friend class ReentryStream;
	friend class vObject;

public:
	vVessel( OBJHANDLE _obj, Scene * scene );
	virtual ~vVessel();

	static void GlobalInit(TextureMgr * TM, D3D11Client * gc);
	static void GlobalExit(TextureMgr * TM);

	int VisEvent( DWORD msg, UINT context );
	MESHHANDLE clbkGetMesh( UINT idx );

	void SaveData();
	void Update();

	//renders vessel sahdows
	void RenderShadows( );
	//mesh
	static void InitRender();
	static void RenderCompleted();
	static void InitRenderShadowMap();
	static void RenderShadowMapCompleted();
	void Render();
	//focus vessel only:
	//cockpit and VC
	void RenderCockpit();
	void RenderVC();

	void NotifyParticleStreamAttached(D3D11ParticleStream * ps);

	//beacons, exhaust and reentry billboards
	static void InitRenderBeacons();
	static void RenderBeaconsCompleted();
	static void InitRenderExhaust();
	void RenderBeacons();
	void RenderExhaust();
	void RenderReentry();
	void RenderBoundingBox();

	float GetBoundingSphereRad( );

	//bounding sphere:
	D3DXVECTOR3 AABB[2];
	float bsRad;
	bool bsRecompute;
protected:
	void CheckResolution() {	}

	void Animate( UINT midx, UINT anim, double state );
	void AnimateComponent( ANIMATIONCOMP *AnimComp, D3DXMATRIX &T );
	void TransformPoint( VECTOR3 &p, D3DXMATRIX &T );
	void TransformDirection( VECTOR3 &a, D3DXMATRIX &T, bool normalize );

	int InsertMesh( UINT idx );
	int DelMesh( UINT idx );
	int SetVisibilityMode( UINT idx );
	int SetMeshOffset( UINT idx );

	int ResetAnimations( UINT idx );
	int ClearAnimations( UINT idx );
	int DelAnimation( UINT idx );
	int NewAnimation( UINT idx );

	VESSEL *VSL;

	VECTOR3 CDir;
	DWORD nex;
	double MaxExhaustLenght, simt, nxtsimt;

//animations:
	ANIMATION *ANIM;
	double *animstate;
	UINT nanim;

	DWORD nbls, nblsmax;
	struct BeaconData {
		BEACONLIGHTSPEC bls;
		VECTOR3 pos;
		VECTOR3 col;
	} *BC;

	struct ExhaustData {
		VECTOR3
			ldir,
			lpos;

		double
			level,
			modulate,
			wsize,
			lsize,
			lofs;

		Texture *tex;
	} *espc;

	struct ReentryData {
		double pressure, airspeed, size;
		VECTOR3 d;
	} rspc;

//meshes:
	struct VSLMESH {
		D3D11Mesh *MSH;
		WORD vis_mode;
		D3DXMATRIX ofs;
	} *MESH;
	DWORD nmesh;

//current sun light:
	Sun_spec SunLight;

	static BBVertex  _VB[8];

	static ID3D11InputLayout
		*IL_BillBoard;
	static ID3D11VertexShader
		*VS_BillBoard;
	static ID3D11PixelShader
		*PS_BillBoard;
	static ID3D11Buffer
		*VB, *IB;
public:
	static Texture
		*Ball[3],
		*def_Exhaust,
		*def_Reentry;
	static ID3D11Buffer * cb_vs_ShadowMap, * cb_ps_ShadowMap, * cb_gs_ShadowMap;
protected:

	bool update_vc, bAMSO;
	VCHUDSPEC specHUD;
	VCMFDSPEC specMFD[MAXMFD];
	Texture *texHUD, *texMFD[MAXMFD];
	DWORD nmfd;
private:
	static CComPtrEx<ID3D11VertexShader> VS_Mesh, VS_ShadowMap;				//Vessel.fx
	static CComPtrEx<ID3D11PixelShader> PS_Mesh;

	static CComPtrEx<ID3D11GeometryShader> GS_ShadowMap;

	static CComPtrEx<ID3D11InputLayout> IL_ShadowMap;

	static ID3D11Buffer * beaconsBuffer;
	std::vector<D3D11ParticleStream *> m_particleStreams;
};

//=====================================
//		Stars
//=====================================
//	Sun

class vStar : public vObject
{
	friend class vObject;
	friend class vVessel;
public:
	vStar( OBJHANDLE _obj, Scene * scene ) ;
	virtual ~vStar();

	static void GlobalInit(TextureMgr * TM);
	static void GlobalExit(TextureMgr * TM);

	int VisEvent( DWORD msg, UINT context ) {	return 0; }
	MESHHANDLE clbkGetMesh( UINT idx ) { return NULL; }

	void Update();
	void Render();

	static Texture *Tex;
	static ID3D11InputLayout *IL_BBVertex;
	static ID3D11VertexShader *VS;
	static ID3D11PixelShader *PS;
	static ID3D11Buffer *VB;
protected:
	void CheckResolution() {	}

	double size;
	double maxdist;
};

//=====================================
//		Surface bases
//=====================================

#define BASE_LIGHT_RENDER_FRONT (0x1)
#define BASE_LIGHT_RENDER_BACK (0x2)
#define BASE_LIGHT_RENDER_ALWAYS (BASE_LIGHT_RENDER_FRONT | BASE_LIGHT_RENDER_BACK)


struct TextureBlock
{
	std::string TextureName;
	double UScale;
	double VScale;
};

struct RunwayLightsObject
{
	VECTOR3 End1;
	VECTOR3 End2;
	double Width;
	int Count;
	VECTOR3 PAPI;
	VECTOR3 VASI;
	double TouchZoneDisplacement;
	double TouchZoneLength;
	double DecisionDistance;
	double ApproachStart;
};

struct BeaconArrayObject
{
	VECTOR3 End1;
	VECTOR3 End2;
	int Count;
	double Size;
	VECTOR3 Color;
};

enum ObjectType
{
	ObjectType_RunwayLights = 1,
	ObjectType_BeaconArray = 2,
	ObjectType_Other = 3
};

const double RunningLightsInterval = 0.05;

class vBase : public vObject
{
public:
	vBase( vPlanet *_PLN, OBJHANDLE _planet, OBJHANDLE _obj, const ConfigFileParser * config, Scene * scene );
	virtual ~vBase();

	int VisEvent( DWORD msg, UINT context ) { return 0; }
	MESHHANDLE clbkGetMesh( UINT idx ) { return NULL; }

	void Update();

	void RenderSurface();
	void RenderStructuresBS();
	void RenderStructuresAS();

	static void InitRenderShadows();
	static void InitRenderBaseLights();
	void RenderShadows();
	void RenderBaseLights();

	//base craters:
	double GetBaseMeshRadius();
private:
	void CheckResolution() {	}
	void SetupShadowMeshes();
	void InitBaseLights();

	void InitShaders();

	const ConfigFileParser * m_config;

	//time vars...

//tiles and meshes:
	const SurftileSpec *tspec;
	DWORD
		ntile,
		nstructs_bs,
		nstructs_as,
		nshadow_mesh;

	D3D11Mesh
		*tilemesh,		//meshes for base tiles
		**structs_bs,	//structures before shadows
		**structs_as;	//structures after shadows

	bool p_night;		//use night textures for base objects
	//local lights to do...

	struct ShadowMesh {
		ID3D11Buffer *VB, *IB;
		DWORD nvtx, nidx;
		double ecorr;
	} *shadow_mesh;

	DWORD nshmesh;
	OBJHANDLE planet;
	vPlanet *PLN;

	struct RPARAM {
		MATRIX3 vR;
		VECTOR3
			pp,
			sd;
	} RP;

	Sun_spec SunLight;

	struct BaseLight
	{
		VECTOR3 Pos;
		VECTOR3 Dir;
		D3DXVECTOR4 Color;
		D3DXVECTOR4 BackColor;
		BYTE RenderFlags;
		bool forceDisable;
	};

	typedef std::vector<UINT> BaseLightsGroupVector;
	typedef std::vector<BaseLightsGroupVector> RunningLightsVector;
	struct RunningLightsSystem
	{
		RunningLightsVector lightGroups;
		UINT disabledGroupIndex;
	};

	std::vector<RunningLightsSystem> m_runningLightsSystems;
	double m_previousSimTime;

	void UpdateRunningLightsSystem(RunningLightsSystem& lightsSystem, double timeInterval);

	struct PAPILight
	{
		VECTOR3 Position;
		double angle;
	};

	struct PAPILightsSystem
	{
		VECTOR3 ApproachDirection;
		PAPILight Lights[4];
		D3DXVECTOR4 BelowColor;
		D3DXVECTOR4 AboveColor;
	};

	struct VASILight
	{
		VECTOR3 Position;
		double angle;
	};

	struct VASILightsSystem
	{
		VECTOR3 ApproachDirection;
		VASILight Lights[8];
		D3DXVECTOR4 BelowColor;
		D3DXVECTOR4 AboveColor;
	};

	void InitPAPILights(const RunwayLightsObject& obj, const VECTOR3& rwDir, const VECTOR3& tangentDir, bool isFrontEnd);
	void InitVASILights(const RunwayLightsObject& obj, const VECTOR3& rwDir, const VECTOR3& tangentDir, bool isFrontEnd);
	void InitTouchZoneBorder(const RunwayLightsObject& obj, const VECTOR3& rwDir, const VECTOR3& tangentDir, bool isFrontEnd);
	void InitTouchZoneMarkings(const RunwayLightsObject& obj, const VECTOR3& rwDir, const VECTOR3& tangentDir, 
		const VECTOR3& frontOffset, const VECTOR3& backOffset, bool isFrontEnd);
	void InitApproachZoneMarkings(const RunwayLightsObject& obj, const VECTOR3& rwDir, const VECTOR3& tangentDir, 
		const VECTOR3& frontOffset, const VECTOR3& backOffset, bool isFrontEnd);

	std::vector<PAPILightsSystem> m_papiLights;
	std::vector<VASILightsSystem> m_vasiLights;
	std::vector<BaseLight> m_baseLights;

	CComPtrEx<ID3D11PixelShader> m_pixelShader;

	CComPtrEx<ID3D11VertexShader> m_baseLightsVS;
	CComPtrEx<ID3D11PixelShader> m_baseLightsPS;
};

#endif
